package avicit.bdp.dds.api.service;


import avicit.bdp.common.base.BaseService;
import avicit.bdp.dds.api.dto.FunctionDTO;
import avicit.bdp.dds.dao.entity.FunctionCondition;
import avicit.bdp.dds.dao.mapper.FunctionDAO;
import avicit.platform6.core.exception.BusinessException;
import avicit.platform6.core.exception.BusinessException;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;


/**
 * 基础函数表服务
 */
@Transactional
@Service
public class FunctionService extends BaseService<FunctionDAO, FunctionDTO> {

    //常用操作符  (注 切割时 | || 无法实现 用# ## 代替)
    private static final String[] funOperatorArray = {"<=>", "<>", "==", ">=", "<=", "&&", "##", "!=", "!",  "%", "&",
            "+", "-", "*", "/", "<", ">", "=",  "^", "#"};

    //常用操作符（返回boolean类型）
    private static final String[] funOperatorBooleanArray = {"<=>", "<>", "==", ">=", "<=", "&&", "##", "!=", "!",
            "&", "<",  ">", "=",  "#"};

    /**
     * 获取函数树
     *
     * @param	type
     * @return java.util.List<avicit.bdp.phm.dto.FunctionDTO>
     *
     * @author felix
     * @date 2022/6/13 10:46
     */
    public List<FunctionDTO> getFunctionTree(String type,String name) {
        try {
            //非末级节点
            List<FunctionDTO> dataList = this.mapper.selectTopFunctionList();
            Map<String, FunctionDTO> allFunctionMap = new HashMap<>();
            for (FunctionDTO functionDTO : dataList) {
                allFunctionMap.put(functionDTO.getId(), functionDTO);
            }

            //查询对应的末级节点
            List<FunctionDTO> functionList = this.mapper.getAllFunctionByName(type,name);

            //中转list
            List<FunctionDTO> list = new ArrayList<>();
            list.addAll(functionList);

            handleFunctionTreeList(list,functionList,allFunctionMap);

            Map<String, List<FunctionDTO>> map = Maps.newHashMap();
            List<FunctionDTO> treeList = new ArrayList<>();

            list = list.stream().sorted(Comparator.comparing(FunctionDTO::getOrderBy, Comparator.nullsLast(Integer::compareTo))).collect(Collectors.toList());//排序
            if (CollectionUtils.isNotEmpty(list)) {
                for (FunctionDTO functionDTO : list) {
                    if ("-1".equals(functionDTO.getParentId())) {
                        treeList.add(functionDTO);
                    } else {
                        if (map.containsKey(functionDTO.getParentId())) {
                            map.get(functionDTO.getParentId()).add(functionDTO);
                        } else {
                            List<FunctionDTO> functionDTOS = Lists.newArrayList();
                            functionDTOS.add(functionDTO);
                            map.put(functionDTO.getParentId(), functionDTOS);
                        }
                    }
                }
            }
            listConvert(treeList, map);

            return treeList;
        } catch (Exception e) {
            throw new BusinessException(e.getMessage(), e);
        }
    }

    private void listConvert(List<FunctionDTO> list, Map<String, List<FunctionDTO>> map) {
        for (FunctionDTO functionDTO : list) {
            List<FunctionDTO> functionDTOS = map.get(functionDTO.getId());
            if (CollectionUtils.isNotEmpty(functionDTOS)) {
                listConvert(functionDTOS, map);
                functionDTO.setChildren(functionDTOS);
            } else {
                functionDTO.setChildren(null);
            }
        }
    }

    /**
     * 此方法为筛选必要的非末级节点
     *
     * @param	list
     * @param	functionList
     * @param	allFunctionMap
     * @return void
     *
     * @author felix
     * @date 2022/6/10 9:43
     */
    private void handleFunctionTreeList(List<FunctionDTO> list, List<FunctionDTO> functionList,
                                                     Map<String, FunctionDTO> allFunctionMap) {
        for (FunctionDTO functionDTO : functionList) {
            if(!functionDTO.getParentId().equals("-1")){
                FunctionDTO function = allFunctionMap.get(functionDTO.getParentId());
                if(!list.contains(function)){
                    list.add(function);
                }
                List<FunctionDTO> functions = new ArrayList<>();
                functions.add(function);
                handleFunctionTreeList(list,functions,allFunctionMap);
            }
        }
    }

    /**
     * 函数校验
     *
     * @param	functionCondition
     * @return java.lang.Boolean
     *
     * @author felix
     * @date 2022/6/13 10:46
     */
    public Boolean validateFunction(FunctionCondition functionCondition) {

        String type = functionCondition.getType();
        if (StringUtils.isBlank(type)) {
            throw new BusinessException("校验失败！");
        }

        Integer resultType  = functionCondition.getResultType();
        if (resultType == null) {
            throw new BusinessException("校验失败！");
        }

        String expression  = functionCondition.getExpression();
        if (StringUtils.isBlank(expression)) {
            throw new BusinessException("校验失败！");
        }

        if("flownode".equals(type)){
            List<String> funParams = functionCondition.getFunParams();
            if(CollectionUtils.isEmpty(funParams)){
                throw new BusinessException("校验失败！");
            }
        }

        //去除表达式多余空格
        expression = mergeBlank(expression);
        //去除收尾空格
        expression = trim(expression);

        //|替换#
        expression = expression.replaceAll("\\|","#");

        //检查表达式括号
        if(expression.contains("(")){
            if(!checkArentheses(expression)){
                return false;
            }
        }

        //假设正确平衡括号,并且没有嵌套括号,以下将删除括号内的所有空格(并且仅在那里):
        //String resultString = subjectString.replaceAll("\\s+(?=[^()]*\\))", "");
        //循环判断括号位置匹配正确的一对括号


        //相邻的两个字符不能没有操作符
        if(!checkSpace(expression)){
            return false;
        }

        //处理函数内的操作符 如果是括号内的不视为运算符
        List<String> sourceChar = new ArrayList<>();

        expression = replaceExpression(funOperatorArray,expression,sourceChar);


        //处理操作符
        String splitStr = handleFunOperatorArray(funOperatorArray);

        //切割表达式
        String[] valueArrTmp = expression.split(splitStr);

        //去除 -0.1的符号 被分割成""
        String[] valueArr  = Arrays.stream(valueArrTmp).filter(i -> !i.trim().equals("")).toArray(String[]::new);


        //将修改的操作符还原
        for (int i = 0;i<valueArr.length;i++) {
            for(int j = 0;j<valueArr[i].length();j++){
                if("?".equals(valueArr[i].substring(j,j+1))){
                    valueArr[i] = valueArr[i].substring(0,j) + sourceChar.get(0) + valueArr[i].substring(j+1);
                    sourceChar.remove(0);
                }
            }
        }


        //查询对应的末级节点函数
        List<FunctionDTO> functionList = this.mapper.getAllFunction(type,null);
        List<String> functionName = new ArrayList<>();
        if(CollectionUtils.isNotEmpty(functionList)){
            for (FunctionDTO functionDTO : functionList) {
                functionName.add(functionDTO.getName());
            }
        }

        //判断返回值是否正确
        List<Boolean> booleanList = new ArrayList<>();
        //如果返回值是boolean类型  如果表达式存在返回boolean类型的操作符 视为返回boolean值
        for (String fun : funOperatorBooleanArray) {
            booleanList.add(expression.contains(fun));
        }

        //查询对应的末级节点函数（返回boolean类型）
        List<FunctionDTO> functionBooleanList = this.mapper.getAllFunction(type,2);
        List<String> functionBooleanName = new ArrayList<>();
        if(CollectionUtils.isNotEmpty(functionBooleanList)){
            for (FunctionDTO functionDTO : functionBooleanList) {
                functionBooleanName.add(functionDTO.getName());
            }
        }

        //如果返回值类型为1- 固定值  那么不能包含Boolean类型操作符
        /*if(resultType == 1){
            //如果返回值为固定值 但是包含了Boolean类型操作符 则不合法
            if(valueArr.length==1){
                //只有一个函数 不能是boolean类型函数
                boolean flag = handleBooleanFun(expression,functionBooleanName);
                if(flag){
                    return false;
                }
            }else if(booleanList.contains(true)){
                return false;
            }
            //如果返回值类型为2- boolwean值
        }else*/ if(resultType == 2){
            if(valueArr.length==1){
                //只有一个函数 只能是boolean类型函数
                boolean flag = handleBooleanFun(expression,functionBooleanName);
                if(!flag){
                    return false;
                }
            }else if(!booleanList.contains(true)){
                return false;
            }
        }

        //参数集合
        List<String> params = new ArrayList<>();

        //函数集合(函数也放在参数集合中)
        List<String> functions = new ArrayList<>();

        //处理函数
        handleExpression(params,functions,valueArr);

        //验证参数
        if(CollectionUtils.isNotEmpty(params)){
            List<String> funParams = functionCondition.getFunParams();
            //如果funparams为空 证明表达式中的字符串不合法
            if(CollectionUtils.isEmpty(funParams)){
                return false;
            }
            for (String param : params) {
                //如果字符参数不是在选择中的参数列表中则不合法
                if(!funParams.contains(param)){
                    return false;
                }
            }
        }


        //验证函数 函数是否是自己的函数
        if(CollectionUtils.isNotEmpty(functions)){
            for (String function : functions) {
                Boolean flag = handleFunction(function,functionName);
                if(!flag){
                    return false;
                }
            }

        }


        return true;
    }

    //判断当前位置是否是空格以及连续空格的个数(递归)
    public static int getBlankNumber(String s, int index)
    {
        if (index < s.length()) {
            if (s.charAt(index) == ' ') {
                return getBlankNumber(s, index + 1) + 1;
            } else {
                return 0;
            }
        } else {
            return 0;
        }
    }

    //使用 String 对象自带的 substring() 方法，将字符串分割为两部分，去掉中间的空格，再连接起来，使连续多个空格变为一个
    public static String mergeBlank(String s)
    {
        int numberBlank = 0;
        String a1;//字符串的第一部分
        String a2;//字符串的第二部分
        for (int index = 0; index < s.length(); index++) {//循环整个字符串，判断是否有连续空格
            numberBlank = getBlankNumber(s, index);
            if (numberBlank >= 2) {//根据连续空格的个数以及当前的位置，截取字符串
                a1 = s.substring(0, index);
                a2 = s.substring(index + numberBlank - 1);
                s = a1 + a2;//合并字符串
            }
        }
        return s;
    }

    //去除首尾空格
    public static String trim(String s)
    {
        if (s.charAt(0) == ' ') {
            s = s.substring(1);
        }
        if (s.charAt(s.length() - 1) == ' ') {
            s = s.substring(0, s.length() - 1);
        }
        return s;
    }

    //判断空格两边是否存在操作符  不存在返回false
    private boolean checkSpace(String expression) {
        List<String> list = new ArrayList<>();
        for (String s : funOperatorArray) {
            list.add(s);
        }
        String[] splited = expression.split("\\s+");
        for(int i = 0;i<splited.length-1;i++){
            //忽略括号左右的空格
            if(splited[i].contains("(")||splited[i].contains(")")||splited[i+1].contains("(")||splited[i+1].contains(
                    ")")){
                continue;
            }
            if(!list.contains(splited[i])&&!list.contains(splited[i+1])){
                return false;
            }
        }
        return true;
    }

    private String replaceExpression(String[] funOperatorArray, String expression, List<String> sourceChar) {
        for (String array : funOperatorArray) {
            for (int i = 0; i <= expression.length() - 1; i++) {
                if(array.equals(expression.substring(i,i+1))){
                    //判断此操作符之前的字符括号是否合规  不合规证明此操作符在括号内  那么暂时将操作符替换成“?”
                    if(expression.substring(0,i).contains("(")&&(!checkArentheses(expression.substring(0,i)))){
                        sourceChar.add(array);
                        expression = expression.substring(0,i) + "?" + expression.substring(i+1);
                    }
                }
            }
        }
        return expression;
    }


    /**
     * 判断左右括号个数是否匹配
     *
     * @param	expression
     * @return void
     *
     * @author felix
     * @date 2022/6/13 14:25
     */
    private boolean checkArentheses(String expression) {
        // 计数(出现了几次
        int x = 0;
        // 计数)出现了几次
        int y = 0;
        // 遍历数组的每个元素
        for (int i = 0; i <= expression.length() - 1; i++) {
        // 因为i的最大数是str长度-1,这里要+1;
            String getstr = expression.substring(i, i + 1);
            if (getstr.equals("(")) {
                x++;
            }
            if (getstr.equals(")")) {
                y++;
            }
        }
        if(x!=y){
            return false;
        }
        return true;
    }

    //判断函数是否为授权函数
    private Boolean handleFunction(String function, List<String> functionName) {
        String funName = function.trim().substring(0,function.indexOf("(")).trim();
        if(!functionName.contains(funName)){
            return false;
        }
        //判断函数是否嵌套函数
        String newFunName = function.trim().substring(function.indexOf("(")+1,function.length()-1);
        if(newFunName.contains("(")&&newFunName.endsWith(")")){
            handleFunction(newFunName,functionName);
        }

        return true;
    }

    //判断函数是否为boolean类型函数
    private boolean handleBooleanFun(String expression, List<String> functionName) {
        String newExpression = expression.trim();
        if(newExpression.contains("(")&&newExpression.endsWith(")")){
            String funName = newExpression.substring(0,newExpression.indexOf("(")).trim();
            if(!functionName.contains(funName)){
                return false;
            }
        }else {//没有操作符 只能是单独的函数
            return false;
        }
        return true;
    }

    /**
     * 处理表达式
     *
     * @param	params
     * @param	functions
     * @param	valueArr
     * @return void
     *
     * @author felix
     * @date 2022/6/13 11:15
     */
    private void handleExpression(List<String> params, List<String> functions, String[] valueArr) {

        for (String valueStr : valueArr) {
            if(!isNumberString(valueStr.trim())){
                if(valueStr.trim().contains("(")&&valueStr.trim().endsWith(")")){
                    functions.add(valueStr.trim());
                }else {
                    params.add(valueStr.trim());
                }
            }
        }
    }
    /**private void handleExpression(List<String> params, String[] valueArr) {

        for (String valueStr : valueArr) {
            if(!isNumberString(valueStr.trim())&&!"".equals(valueStr.trim())){
                params.add(valueStr.trim());
            }
        }
    }**/

    /**
     * 正则表达式判断是否是数字字符串（可判断正数，负数和小数）
     *
     * @param	str
     * @return boolean
     *
     * @author felix
     * @date 2022/6/13 11:17
     */
    private boolean isNumberString(String str) {
        java.util.regex.Pattern pattern = java.util.regex.Pattern.compile("-?[0-9]+(\\.[0-9]+)?");
        return pattern.matcher(str).matches();
    }

    /**
     * 处理常用操作符
     *
     * @param	funOperatorArray
     * @return java.lang.String
     *
     * @author felix
     * @date 2022/6/13 10:56
     */
    private String handleFunOperatorArray(String[] funOperatorArray) {
        String splitStr = "";
        for (int i = 0; i < funOperatorArray.length ; i++) {
            if(i == funOperatorArray.length - 1){
                splitStr += "\\"+funOperatorArray[i];
            }else {
                splitStr += "\\"+funOperatorArray[i] + "|";
            }
        }
        return splitStr;
    }
}
